/**
 * 
 */
package programme;

import in_out.Parser_PF;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;

/**
 * @author chewbie
 * 
 */
public class PortefeuilleDeterministe extends ProgDeterministe implements Portefeuille {

	/** Nombre de titres à selectionner*/ 
	private int K;
	
	/** Proportion maximum pour chaque titre*/
	private double delta;
	
	/** Proportion minimum pour chaque titre*/
	private double epsilon;
	
	/** Nombre de titres du portefeuille */
	protected int nbTitres;
	
	/** Nom du fichier définissant le portefeuille */
	protected String filename;
	
	/** Esperance desire du portefeuille */
	protected double esperance_portefeuille;
	
	
	/**
	 * Equivalent à un constructeur par copie
	 * Prend tt les arguments ayant aboutit à la creation de pf et recrée un PortefeuilleDeterministe
	 * à partir de ceux ci
	 * @param pf PortefeuilleDeterministe à copier
	 */
	public PortefeuilleDeterministe(PortefeuilleDeterministe pf){
		this(pf.getFilename(), pf.getK(), pf.getEpsilon(), pf.getDelta(), pf.getEsperance_portefeuille());
	}
	
	public PortefeuilleDeterministe(){
		super();
	}
	
	/**
	 * Constructeur du PortefeulleDeterministe
	 * prend un argument un nom de fichier pour aller chercher les infos necessaire dans les fichiers
	 * Attention le nom de fichier ne doit pas comporter d extension et l'on suppose que les 2 fichiers 
	 * nécessaire sont nommé : nom_de_fichier+".txt" et nom_de_fichier+"_FE.txt"
	 * Example: PortefeuilleDeterministe("DAX", k, epsilon, delta, ro)
	 * 			ouvrira les fichiers "DAX.txt" et "DAX_FE.txt"
	 * @param nom_fichier
	 * @param K
	 * @param epsilon
	 * @param delta
	 * @param esperance_desire
	 */
	
	public PortefeuilleDeterministe(String nom_fichier, int K, double epsilon, double delta, double esperance_desire){
		super();
		Parser_PF parser = new Parser_PF(nom_fichier); 
		filename = nom_fichier;
		esperance_portefeuille = esperance_desire;
		int nbTitres = parser.getNbTitres(); 
		Hashtable<Integer, Hashtable<Integer, Double>> covariances = parser.getCovariances();
		Hashtable<Integer,Double> rendements = parser.getRendements();
		
		// Attribue nbTitres (attribut de programme) et crée le bon nombre de variables
		setNbTitres(nbTitres);
		
		// Creation de la fonction objectif
		ArrayList<Variable> titres = getTitres();
		Expression e = new Expression(this);
		for (Variable v1:titres){
			for (Variable v2:titres){
				double covariance = covariances.get(v1.getNum()).get(v2.getNum());
				e.addProduit(covariance, v1, v2);
			}
		}	
		objectif = new FonctObjectif(true, e);
		
		// Somme des xi = 1
		e = new Expression(this);
		for (Variable v1:titres){
			e.addSomme(1, v1);
		}
		contraintes.add(new Contrainte(e, TypeContrainte.EGAL, 1, false));		
		
		// Somme des mu_i*xi >= p
		e = new Expression(this);
		for (Variable v1:getTitres()){
			e.addSomme(rendements.get(v1.getNum()), v1);
		}
		contraintes.add(new Contrainte(e, TypeContrainte.SUP, esperance_desire, false));
		
		setK(K);
		setEpsilon(epsilon);
		setDelta(delta);
		setRo(esperance_desire);
	}	
	
	/**
	 * Definit nbTitres et crée les variables xi et yi (avec i allant de 0 à nbTitres-1
	 * @param nbTitres
	 */
	public void setNbTitres(int nbTitres){
		// On attribue le nb de titres et créé le bon nombre de variables
		this.nbTitres = nbTitres;
		
		// Creation des Variables
		addVecteurVariables(new VecteurVariables("Titres", nbTitres, TypeVariable.CONTINUE, 0, 1));
		addVecteurVariables(new VecteurVariables("Choix", nbTitres, TypeVariable.BOOLEEN));
	}
	
	public int getK() {
		return K;
	}
	/**
	 * Definit K et crée la contrainte Somme des yi = K
	 * @param k
	 */
	public void setK(int k) {
		// on fixe le K en attribut
		K = k;
		
		// on ajoute la contrainte disant que le nombre de titre selectionné est égal à K
		ArrayList<Variable> choix = this.getChoix();
		Expression e = new Expression(this);
		for (Variable v1:choix){
			e.addVar(v1);
		}
		
		contraintes.add(new Contrainte(e, TypeContrainte.EGAL, k, false));
		
	}
	
	public void setRo(double ro){

	}

	public double getDelta() {
		return delta;
	}
	/**
	 * Definit les deltas et crée la contrainte epsiloni*yi - xi <= 0
	 * @param delta
	 */
	public void setDelta(double delta) {
		this.delta = delta;
		// on ajoute la contrainte disant que le nombre de titre selectionné est égal à K
		ArrayList<Variable> titres = this.getTitres();
		ArrayList<Variable> choix = this.getChoix();
		
		
		for (int i=0; i<nbTitres; i++){
			Expression e = new Expression(this);
			e.addSomme(delta, choix.get(i));
			e.addSomme(-1, titres.get(i));
			contraintes.add(new Contrainte(e, TypeContrainte.SUP, 0, true));
		}
		
		
	}

	public double getEpsilon() {
		return epsilon;
	}
	
	/**
	 * Definit les epsilon et crée la contrainte epsiloni*yi - xi <= 0
	 * @param epsilon
	 */
	
	public void setEpsilon(double epsilon) {
		this.epsilon = epsilon;
		// on ajoute la contrainte disant que le nombre de titre selectionné est égal à K
		ArrayList<Variable> titres = this.getTitres();
		ArrayList<Variable> choix = this.getChoix();
		
		
		for (int i=0; i<nbTitres; i++){
			Expression e = new Expression(this);
			e.addSomme(epsilon, choix.get(i));
			e.addSomme(-1, titres.get(i));
			contraintes.add(new Contrainte(e, TypeContrainte.INF, 0, true));
		}
		
		
	}
	
	/** Linearise la fonction objectif 
	 * pour fin de tests */
	public void lineariser(){
		objectif.getFonction().lineariser(); 
	}
	
	public PortefeuilleDeterministe lineariserFonctObj(){
		PortefeuilleDeterministe portefeuille = new PortefeuilleDeterministe(this);
		portefeuille.lineariser();
		return portefeuille;
	}
	
	/** Les xi */
	public ArrayList<Variable> getTitres(){
		return variables.get("Titres").getVariables();
	}
	
	/** Les yi */
	public ArrayList<Variable> getChoix(){
		return variables.get("Choix").getVariables();
	}

	public String getFilename() {
		return filename;
	}

	public void setFilename(String filename) {
		this.filename = filename;
	}

	public int getNbTitres() {
		return nbTitres;
	}

	public double getEsperance_portefeuille() {
		return esperance_portefeuille;
	}

	public void setEsperance_portefeuille(double esperance_portefeuille) {
		this.esperance_portefeuille = esperance_portefeuille;
	}


}
